/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package csgui.test;

import csgui.PacketSchedulerEnum;
import csgui.entities.Broker;
import csgui.entities.ComputingResource;
import csgui.entities.Experiment;
import csgui.entities.GridSimEntity;
import csgui.entities.Holiday;
import csgui.entities.Router;
import csgui.entities.User;
import csgui.entities.Weekend;
import gridsim.AllocPolicy;
import gridsim.GridResource;
import gridsim.GridSim;
import gridsim.Machine;
import gridsim.MachineList;
import gridsim.ParameterException;
import gridsim.ResourceCalendar;
import gridsim.ResourceCharacteristics;
import gridsim.auction.AuctionObserver;
import gridsim.auction.Message;
import gridsim.auction.MessageCallForBids;
import gridsim.auction.MessageInformOutcome;
import gridsim.auction.MessageInformStart;
import gridsim.auction.MessageRejectBid;
import gridsim.auction.Responder;
import gridsim.net.FIFOScheduler;
import gridsim.net.Link;
import gridsim.net.PacketScheduler;
import gridsim.net.RIPRouter;
import gridsim.net.RateControlledScheduler;
import gridsim.net.SCFQScheduler;
import gridsim.net.SimpleLink;
import gridsim.net.fnb.ARED;
import gridsim.net.fnb.FIFO;
import gridsim.net.fnb.FnbSCFQScheduler;
import gridsim.net.fnb.RED;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

/**
 *
 * @author robert
 */
public class ReadTest2 {
    
    public static void main(String[] args)
    {
        new ReadTest(args[0]);
    }
    @SuppressWarnings("empty-statement")
    public ReadTest2(String experimentName)
    {   
        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory( "csguiPU");
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        
        System.out.println("Number of db records:"+entityManager.createQuery("select e from Experiment e WHERE name=:name").setParameter("name", experimentName).getResultList().size());
        Experiment experiment = null;
        if(entityManager.createQuery("select e from Experiment e WHERE name=:name").setParameter("name", experimentName).getResultList().size()>0)
        {
            experiment = (Experiment)entityManager.createQuery("select e from Experiment e WHERE name=:name").setParameter("name", experimentName).getSingleResult();
        }
        // TODO start asynchronous download of heavy resources
        entityManager.close();
        ArrayList<GridSimEntity> entities = (ArrayList<GridSimEntity>) experiment.getGridSimEntities();
        int userCount = 0;
        @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
        Collection<Broker> brokers = new ArrayList<>();
        Collection<ComputingResource> nodes = new ArrayList<>();
        AuctioneerBroker auctioneerBroker = null;
        
        for(GridSimEntity entity : entities)
        {
            if(entity instanceof Broker)
            {
                if(brokers.size()==0)
                {
                    Broker _broker = (Broker)entity;
                    try {
                        auctioneerBroker = new AuctioneerBroker(_broker.getName(),_broker.getBaudRate(),_broker.getPropagationDelay(),_broker.getMtu(),_broker.getUsers().size());
                    } catch (Exception ex) {
                        Logger.getLogger(ReadTest.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                brokers.add((Broker)entity);
            }
            if(entity instanceof User)
            {
                userCount++;
            }
            if(entity instanceof ComputingResource)
            {
                nodes.add((ComputingResource)entity);
            }
        }
        @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
        ArrayList<NetUser> userList;
        userList = new ArrayList<>(userCount);
        int counter = 1;
        for(GridSimEntity entity : entities)
        {
            if(entity instanceof User)
            {
                NetUser _user = null;
                User user = (User)entity;
                try {
                    _user = new NetUser("User_" + counter, user.getGridletCount(),user.getBaudRate(), user.getPropagationDelay(), user.getMtu(), auctioneerBroker);
                } catch (Exception ex) {
                    Logger.getLogger(ReadTest.class.getName()).log(Level.SEVERE, null, ex);
                }

                // add a user into a list
                userList.add(_user);
                counter++;
            }
        }
        Date date = new Date(experiment.getSimulationTime());
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        GridSim.init(userCount,calendar,experiment.getTrace());
        MachineList machineList = new MachineList();
        String architecture = "";
        String os = "";
        Double timeZone = 0.0;
        Double cost = 0.0;
        Collection<Weekend> _weekendDays = null;
        Collection<Holiday> _holidays = null;
        Double peakLoad = 0.0;
        Double offPeakLoad = 0.0;
        Double holidayLoad = 0.0;
        long seed = 11L*13*17*19*23+1;
        String name = "";
        Double baudRate = 0.0;
        Double propDelay = 0.0;
        int mtu = 0;
        int characteristics = 0;
        
        for(ComputingResource node : nodes)
        {
            int machineId = 0;
            Collection<csgui.entities.Machine> machines = node.getMachines();
            for(csgui.entities.Machine machine : machines)
            {
                machineList.add(new Machine(machineId,machine.getNumberOfProcessord(),machine.getMipsRating()));
                machineId++;
            }
            
            architecture = node.getArchitecture().getArchitectureName();
            os = node.getOperatingSystem().getOperatingSystemName();
            timeZone = ((double)(node.getTimeZone().getOffset(experiment.getSimulationTime()))/1000)/3600;
            _weekendDays = node.getWeekendDays();
            _holidays = node.getHolidays();
            peakLoad = node.getPeakLoad();
            offPeakLoad = node.getOffPeakLoad();
            holidayLoad = node.getHolidayLoad();
            name = node.getName();
            baudRate = node.getBaudRate();
            propDelay = node.getPropagationDelay();
            mtu = node.getMtu();
            characteristics = node.getCharacteristic().getId();
        }
        LinkedList holidays = new LinkedList();
        for(Holiday holiday : _holidays)
        {
            holidays.add(holiday.getDayOfWeek());
        }
        @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
        LinkedList weekendDays = new LinkedList();
        for(Weekend weekend : _weekendDays)
        {
            weekendDays.add(weekend.getDayOfWeek());
        }
        //TODO: add option to set ResourceCharateristics enum
        ResourceCharacteristics resourceCharacteristics = new ResourceCharacteristics(architecture,os,machineList,characteristics,timeZone,cost);
        ResourceCalendar resourceCalendar = new ResourceCalendar(timeZone, peakLoad,offPeakLoad, holidayLoad, weekendDays, holidays, seed);
        ReadTest2.AuctionResource gridRes = null;
            try {
                //TODO: set up so that there is 1 auctioneer/broker per grid resource
                gridRes = new ReadTest2.AuctionResource(name,new SimpleLink(name + "_link", baudRate, propDelay, mtu),resourceCharacteristics,resourceCalendar, null);
                gridRes.setAuctioneerID(auctioneerBroker.get_id());
        } catch (ParameterException ex) {
            Logger.getLogger(ReadTest.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NullPointerException ex) {
            Logger.getLogger(ReadTest.class.getName()).log(Level.SEVERE, null, ex);
        }
        catch (Exception ex) {
            Logger.getLogger(ReadTest.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        List<gridsim.net.Router> routers = new ArrayList<gridsim.net.Router>();
        for (Iterator<Router> it = experiment.getRouters().iterator(); it.hasNext();) {
            Router _router = it.next();
            gridsim.net.Router router = new RIPRouter(_router.getName(),_router.getTrace());
            for(GridSimEntity host : _router.getGridSimEntity())
            {
                
                if(host instanceof Broker)
                {
                    Broker broker = (Broker)host;
                    CloudBroker cloudBroker = null;
                    try {
                        cloudBroker = new CloudBroker(broker.getName(), broker.getBaudRate(), broker.getPropagationDelay(), broker.getMtu(), broker.getUsers().size());
                        PacketScheduler scheduler = null;
                        if(broker.getPacketSchedulerEnum().equals(PacketSchedulerEnum.ARED))
                        {
                            //TODO: set max probability weight for dropping an incomplete packet (currently 0.0)
                            //TODO: set max buffer size for the router (currently mtu*number of ports)
                            //TODO: Set queue weight (currently set to 0.0)
                            scheduler = new ARED(broker.getName()+"_ARED",broker.getBaudRate(),0.0,(broker.getMtu()*(_router.getGridSimEntity().size()+1)),0.0,_router.getTrace());
                        }
                        else if(broker.getPacketSchedulerEnum().equals(PacketSchedulerEnum.FIFO))
                        {
                            //TODO: set max buffer size for the router (currently mtu*number of ports)
                            //TODO: Set queue weight (currently set to 0.0)
                            scheduler = new FIFO(broker.getName()+"_FIFO",broker.getBaudRate(),(broker.getMtu()*(_router.getGridSimEntity().size()+1)),0.0,_router.getTrace());
                        }
                        else if(broker.getPacketSchedulerEnum().equals(PacketSchedulerEnum.FIFO_SCHEDULER))
                        {
                            scheduler = new FIFOScheduler(broker.getName()+"_FIFOScheduler");
                        }
                        else if(broker.getPacketSchedulerEnum().equals(PacketSchedulerEnum.RATE_CONTROLLED_SCHEDULER))
                        {
                            //TODO: Set number of classes (currently 5)
                            scheduler = new RateControlledScheduler(broker.getName()+"_RateControlledScheduler",broker.getBaudRate(),5);
                        }
                        else if(broker.getPacketSchedulerEnum().equals(PacketSchedulerEnum.RED))
                        {
                            //TODO: max_buf_size - maximum buffer size for routers (currently mtu*number of ports)
                            //TODO: min_th - minimum threshold for RED (currently 0.0)
                            //TODO: max_th - maximum threshold for RED (currently 0.0)
                            //TODO: max_p - maximum drop probability for RED (currently 0.0)
                            //TODO: queue_weight - queue weight for RED (currently 0.0)
                            scheduler = new RED(broker.getName()+"_RED",broker.getBaudRate(),(broker.getMtu()*(_router.getGridSimEntity().size()+1)),0.0,0.0,0.0,0.0,_router.getTrace());
                        }
                        else if(broker.getPacketSchedulerEnum().equals(PacketSchedulerEnum.SCFQ_SCHEDULER))
                        {
                            scheduler = new SCFQScheduler(broker.getName()+"_SCFQScheduler");
                        }
                        router.attachHost(cloudBroker, scheduler);
                    } catch (Exception ex) {
                        Logger.getLogger(ReadTest2.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                if(host instanceof Broker)
                {
                    
                }
                if(host instanceof ComputingResource)
                {
                    
                }
            }
            routers.add(router);
        }
    }
    class AuctionResource extends GridResource
    {
        AuctionObserver observer;
        private int auctioneerId = -1;

        AuctionResource(String name, Link link,
			ResourceCharacteristics resource,
			ResourceCalendar calendar,
			AllocPolicy policy) throws Exception{

		super(name,link,resource,calendar,policy);

		Responder responder = new ReadTest2.ResponderImpl(resource,calendar,policy);
		observer = new AuctionObserver(this.get_id(),"Observer_1",this.output,responder);
	}
        public void setAuctioneerID(int id) 
        {
            auctioneerId = id;
        }
    }
    class ResponderImpl implements Responder
    {
        private ResourceCharacteristics resource;
        
        public ResponderImpl(ResourceCharacteristics resource,
					ResourceCalendar calendar,
					AllocPolicy policy) throws Exception{
		this.resource = resource;
	}
        @Override
        public Message onReceiveCfb(MessageCallForBids mcfb) {
            return null;
        }

        @Override
        public Message onReceiveInformOutcome(MessageInformOutcome mio) {
            return null;
        }

        @Override
        public Message onReceiveRejectProposal(MessageRejectBid mrb) {
            return null;
        }

        @Override
        public Message onReceiveStartAuction(MessageInformStart mis) {
            return null;
        }
        
    }
}
